﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CreditCalc_v03
{
    class Program
    {
        static void Main()
        {
            Console.BackgroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.Black;
            Console.SetCursorPosition(30, 0); Console.WriteLine(" КРЕДИТНЫЙ КАЛЬКУЛЯТОР ");
            Console.ResetColor(); Console.SetCursorPosition(5, 2);
            Console.ForegroundColor = ConsoleColor.DarkGray;
            Console.Write("Данная программа сформирует календарь платежей по заданным вами параметрам КРЕДИТА. Размер ежемесячного платежа равен сумме платежей по телу кредита и комиссии банка. Комиссия банка начисляется ежемесячно классическим способом на остаток от тела кредита в размере согласно годовой процентной ставки. Платежи, которые приходятся на выходные дни, переносятся на ближайшую пятницу, им предшествующую.");
            Console.WriteLine(" После ввода каждого из параметров нажимайте Enter.");
            Console.WriteLine("");
            int x1 = 21; int y1 = 9; //Координаты ввода данных для расчета кредита
            int x2 = 21; int y2 = 10;
            int x3 = 24; int y3 = 11;
            int x4 = 33; int y4 = 12;
            String frameElement = "*"; //Элемент рамки для вывода календаря           
            Console.ForegroundColor = ConsoleColor.Gray; Console.Write("Сумма кредита, грн.:             ");
            decimal amount = (decimal)ReadPosFloatFromConsole(x1, y1);
            Console.ForegroundColor = ConsoleColor.Gray; Console.Write("Годовой процент, %:              ");
            decimal interestRate = (decimal)ReadPosFloatFromConsole(x2, y2);
            Console.ForegroundColor = ConsoleColor.Gray; Console.Write("Дата получения кредита:          ");
            DateTime startDate = ReadDateFromConsole(x3, y3);
            Console.ForegroundColor = ConsoleColor.Gray; Console.Write("Количество ежемесячных платежей: ");
            int numPayments = (int)ReadPosIntFromConsole(x4,y4);
            Payment[] schedule = GenerateSchedule(amount, startDate, interestRate, numPayments);
            decimal[] creditResume = GenerateCreditResume(schedule);
            Console.ResetColor();
            PrintCreditResume(creditResume, frameElement);
            PrintArray(schedule, frameElement);
            Console.SetCursorPosition(0, 8);
            Console.ReadKey();
        }
        static float ReadPosFloatFromConsole(int x, int y)
        {
            try
            {
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                Console.SetCursorPosition(x, y);
                float a = float.Parse(Console.ReadLine());
                if (a > 0)
                {
                    return (a);
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Ошибка ввода, повторите");
                    Console.ResetColor(); Console.SetCursorPosition(x, y);
                    Console.Write("                                              ");
                    Console.SetCursorPosition(x, y);
                    return ReadPosFloatFromConsole(x, y);
                }
            }
            catch
            {
                Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Ошибка ввода, повторите");
                Console.ResetColor();
                Console.SetCursorPosition(x, y);
                Console.Write("                                                  ");
                Console.SetCursorPosition(x, y);
                return ReadPosFloatFromConsole(x, y);
            }
        }
        static uint ReadPosIntFromConsole(int x, int y)
        {
            try
            {
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                Console.SetCursorPosition(x, y);
                uint a = uint.Parse(Console.ReadLine());
                if (a > 0)
                {
                    return (a);
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Ошибка ввода, повторите");
                    Console.ResetColor(); Console.SetCursorPosition(x, y);
                    Console.Write("                                              ");
                    Console.SetCursorPosition(x, y);
                    return ReadPosIntFromConsole(x,y);
                }
            }
            catch
            {
                Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Ошибка ввода, повторите");
                Console.ResetColor();
                Console.SetCursorPosition(x, y);
                Console.Write("                                                  ");
                Console.SetCursorPosition(x, y);
                return ReadPosIntFromConsole(x, y);
            }
        }
        static DateTime ReadDateFromConsole(int x, int y)
        {
            DateTime dt;
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.SetCursorPosition(x, y);
            string s = Console.ReadLine();
            if (DateTime.TryParse(s, out dt))
            {
                return dt;
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Ошибка ввода, повторите");
                Console.ResetColor(); Console.SetCursorPosition(x, y);
                Console.Write("                                              ");
                Console.SetCursorPosition(x, y);
                return ReadDateFromConsole(x, y);
            }
        }
        static Payment[] GenerateSchedule(decimal amount, DateTime startDate, decimal interestRate, int numPayments)
        {
            Payment[] array = new Payment[numPayments];
            Decimal checkamount = amount;
            DateTime checkdate = startDate.AddMonths(1);
            int count = 0;
            while (count < numPayments)
            {
                Payment p = new Payment();
                p.Number = count + 1;
                p.DueDate = checkdate;
                if (checkdate.DayOfWeek == DayOfWeek.Saturday)
                {
                    p.DueDate = checkdate.AddDays(-1);
                }
                else if (checkdate.DayOfWeek == DayOfWeek.Sunday)
                {
                    p.DueDate = checkdate.AddDays(-2);
                }
                p.PrincipalAmount = amount / numPayments;
                if (count == numPayments - 1)
                {
                    p.PrincipalAmount = checkamount;
                }
                var span = checkdate.Subtract(checkdate.AddMonths(-1));
                int days = span.Days;
                p.InterestAmount = checkamount * interestRate * days / 100 / 365;
                array[count] = p;
                checkamount = checkamount - p.PrincipalAmount;
                checkdate = checkdate.AddMonths(1);
                count++;
            }
            return array;
        }
        static decimal[] GenerateCreditResume(Payment[] array)
        {
            decimal interestAmount = 0;
            decimal principalAmount = 0;
            for (int i = 0; i < array.Length; i++)
            {
                Payment p = array[i];
                interestAmount = interestAmount + p.InterestAmount;
                principalAmount = principalAmount + p.PrincipalAmount;
            }
            decimal wholePayment = interestAmount + principalAmount;
            Payment Last = array[array.Length - 1];
            int yearsround = Last.Number / 12;
            decimal years = (decimal)yearsround;
            decimal months = (decimal)Last.Number - years * 12;
            decimal[] creditResume = new decimal[5] { years, months, wholePayment, principalAmount, interestAmount };
            return creditResume;
        }        
        static void PrintArray(Payment[] array,string frameElement)
        {
            Console.SetCursorPosition(32, 25); Console.WriteLine("ПЛАТЕЖНЫЙ КАЛЕНДАРЬ");
            Console.SetCursorPosition(0, 27);
            for (int i = 0; i < array.Length; i++)
            {
                Payment p = array[i];
                decimal payment = p.PrincipalAmount + p.InterestAmount;
                Console.Write("  Платеж {0}: ", p.Number.ToString("000"));
                Console.Write(" {0}  {1}", p.DueDate.ToString("yyyy.MM.dd"), p.DueDate.ToString("ddd"));
                Console.WriteLine("  Сумма,грн: {0} = {1} + {2}", payment.ToString("0.00"), p.PrincipalAmount.ToString("0.00"), p.InterestAmount.ToString("0.00"));                
            }
            Payment last = array[array.Length - 1];
            int ymax = (int)last.Number + 1;
            Console.ForegroundColor = ConsoleColor.DarkYellow;
            PrintFrame(frameElement, ymax);
            Console.ResetColor();
        }
        static void PrintCreditResume(decimal[] array, string frameElement)
        {
            Console.SetCursorPosition(35, 14); Console.WriteLine("РАСЧЕТ КРЕДИТА");
            Console.ForegroundColor = ConsoleColor.DarkYellow;
            for (int n = 0; n < Console.WindowWidth; n++) { Console.Write(frameElement); }
            Console.ResetColor();
            Console.WriteLine("     Раcчетный срок погашения кредита через");
            Console.WriteLine("          годов: {0}", array[0].ToString("0"));
            Console.WriteLine("        месяцев: {0}", array[1].ToString("0"));
            Console.WriteLine("");
            Console.WriteLine("     Сумма всех платежей: {0} грн.", array[2].ToString("0.00"));
            Console.WriteLine("     В том числе,");
            Console.WriteLine("            тело кредита: {0} грн.", array[3].ToString("0.00"));
            Console.WriteLine("          комиссия банка: {0} грн.", array[4].ToString("0.00"));
        }
        protected static int origRow;
        protected static int origCol;
        protected static void WriteAt(string element, int x, int y)
        {
            try
            {
                Console.SetCursorPosition(origCol + x, origRow + y);
                Console.Write(element);
            }
            catch (ArgumentOutOfRangeException e)
            {
                Console.Clear();
                Console.WriteLine(e.Message);
            }
        }
        static void PrintFrame(string frameElement, int ymax)
        {
            origRow = 26;
            origCol = 0;
            //печатает вертикальную левую стенку
            for (int y = 0; y < ymax; y++)
            {
                WriteAt(frameElement, 0, y);
            }
            //печатает горизонтальную нижнюю стенку
            for (int x = 0; x < Console.WindowWidth; x++)
            {
                WriteAt(frameElement, x, ymax);
            }
            //печатает вертикальную правую стенку
            for (int y = ymax; y > 0; y--)
            {
                WriteAt(frameElement, Console.WindowWidth - 1, y);
            }
            //печатает горизонтальную верхнюю стенку
            for (int x = Console.WindowWidth - 1; x > 0; x--)
            {
                WriteAt(frameElement, x, 0);
            }            
            Console.WriteLine();
        }
    }
}
